/** infer
 * infer定义：infer表示在extends条件语句中以占位符出现的用来修饰数据类型的关键字，被修饰的数据类型等使用时才能被推断出来
 * infer占位符的关键字出现的位置：通常innfer出现在以下三个位置上
 * 1) infer出现在extends条件语句后的函数类型的参数类型位置上
 * 2) infer出现在extends条件语句后的函数类型的返回值上
 * 3) infer会出现在类型的泛型具体化类型上
 *  **/

// 1) 函数类型的参数类型位置上
interface Customer {
  username: string
  age: number
}
type custFuncType = (cust: Customer) => string // 函数类型
type inferType<T> = T extends (params: infer P) => any ? P : T
// 如果把上面T具体化为custFuncType，则变为：
// type inferType<custFuncType> = (cust: Customer) => string extends (params: infer P) => any ? P : T
// 这时候(cust: Customer) => string 是可以继承 (params: infer P) => any的，所以应该返回P，通过对比得知P为Customer
type inferResultType = inferType<custFuncType> // Customer

// 2)函数类型的返回值上
type inferType2<T> = T extends (params: any) => infer P ? P : T
// 如果把上面T具体化为custFuncType，则变为：
// type inferType<custFuncType> = (cust: Customer) => string extends (params: any) => infer P ? P : T
// 这时候(cust: Customer) => string 是可以继承 (params: any) => infer P ? P : string
type inferResultType2 = inferType2<custFuncType> // string

// 3)类型的泛型具体化类型上
class Subject {
  constructor(public subid: number, public subname: string) {}
}
let chineseSub = new Subject(100, '语文')
let mathSub = new Subject(120, '数学')
let setZhangsanSubject = new Set<Subject>([chineseSub, mathSub])
type ss =  typeof setZhangsanSubject
type ElementOf<T> = T extends Set<infer E> ? E : never
// 如果把上面T具体化为Set<Subject>，则变为：
// Set<Subject> extends Set<infer E> ? E : never
// 这时候Set<Subject> extends Set<infer E> 通过对比可以知道E为Subject
let result:ElementOf<Set<Subject>>



/** 高级类型 **/
/** 1. Extract
 * 1) 从结果上详细对比Extract泛型约束和类型断言【父子类】
 * 2) 从结果上详细对比Extract泛型约束和类型断言【联合类型】
 * 3) 从结果上详细对比Extract泛型约束和类型断言【函数】
 *  **/
// 1) 父子类
class People {
  name: string
}
class ChinesePeople extends People {
  age: number
}
let cp = new ChinesePeople()

// Extract 是TS提供的一个TS高级type类型【简称TS高级类型】
type Extract<T, U> = T extends U ? T : never
// 定律：子类 extends 父类  返回true=>返回T类型
type extractType = Extract<ChinesePeople, People> // ChinesePeople
// 定律：父类 extends 子类  因为父类继承子类本身不成立，所以一般都是false
// 如果父类跟子类的实例属性和实例方法一样多，extends就是true
type extractType2 = Extract<People, ChinesePeople> // never

// 2) 联合类型
type unionExtractType = Extract<string, string | number> // string
type unionExtractType2 = Extract<string | number, string | number> // string | number
type unionExtractType3 = Extract<string | number, string | number | symbol> // string | number

type unionExtractType4 = Extract<string | number, string> // string
// 这种情况比较特殊，分解判断：会从前面的联合类型的每一个类型去和后面的进行比较
// 第一次 string extends string => string
// 第二次 number extends string => never
// 合起来的结果就是 string | never ， never 类型在联合类型中会被自动忽略，所以最终结果就是 string

// 3) 函数
// 函数类型的泛型约束extends：参数类型和返回值完全相同的情况下
// 参数少的函数类型 extends 参数多的函数类型  返回true
// 参数多的函数类型 extends 参数少的函数类型  返回false
type func1 = (one: number, two: string) => string
type func2 = (one: number) => string
type beginType = Extract<func1, func2> // never
type beginType2 = Extract<func2, func1> // (one: number) => string


// keyof any = string | number | symbol

let obj1: object = { name: 'burt'}
// obj1.name = '哈哈哈' 会报错 类型“object”上不存在属性“name”
let obj2: Record<string, any> = {}
obj2.name // 不会报错，因为Record是一个索引签名，可以是任何string

// Pick作用: 从类型、Type中选择一组属性Keys来创建类型。使用场景示例(从已有类型挑几个需要的属性构造新类型)
// Partial<Type>作用：Partial接收一个泛型类型Type，并将Type所有属性都设置为可选的，返回构造的新类型。
// Omit<Type, Keys>作用: 与Pick相反，Omit是从Type中选取所有Keys属性然后删除构造一个新类型。

export {}